package org.ricks.agent;

import org.ricks.common.IORuntimeException;
import org.ricks.common.bean.BeanUtil;
import org.ricks.ioc.AppContext;
import org.ricks.ioc.Init;
import org.ricks.log.Logger;
import org.ricks.utils.FileUtil;
import org.ricks.utils.ObjectUtil;
import org.ricks.utils.PathUtil;
import org.ricks.utils.ReflectUtil;

import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author chenwei
 * @date 2022/9/111:36
 */
public class DataAgent implements FileListener {
    private static Path path = Paths.get(PathUtil.currPath() + "/data.dat");
    public static Map<String,Map<Integer,Map<String,Object>>> context = new HashMap<>();

    public DataAgent() {
        try {
            reloadData(path);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onCreate(Path file) {
        try {
            reloadData(path);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //重新加载data ，然后调用init 重新初始化内存数据
    @Override
    public void onModify(Path path) {
        File dataFile = path.toFile();
        if(dataFile.getName().endsWith("data.dat")){
            try {
                Logger.info("==========================  data change  ========================");
                Logger.info("==========================  {} byte  ========================",dataFile.length());
                reloadData(path);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            reloadInit();
        }
    }

    @Override
    public void onDelete(Path file) {
        System.err.println("data delete ........");
    }

    public void reloadData(Path path) throws InterruptedException, IOException {
        byte[] bytes = new byte[0];
        try {
            FileInputStream inputStream = new FileInputStream(path.toFile());
            bytes = inputStream.readAllBytes();
            context = ObjectUtil.deserialize(bytes);
            inputStream.close();
        } catch (IORuntimeException e) {
            if(e.getMessage().contains("EOFException")) {
                Logger.warn(" data eof start reload data, curr data byte size：{}" , bytes.length);
                Thread.sleep(100);
                reloadData(path);
            }
        }
    }

    public void reloadInit() {
        List<Object> beans = AppContext.getBeans();
        beans.forEach(bean -> {
            if(bean instanceof Init) ReflectUtil.invoke(bean,"init");
        });
    }

    public static <T> List<T> getBeanList(Class<T> clazz) {
        String name = clazz.getSimpleName().replaceAll("Data","");
        Map<Integer,Map<String,Object>> beanMap = context.get(name);
        return beanMap.values().stream().map(data -> BeanUtil.toBean(data,clazz)).collect(Collectors.toList());
    }

    public static <T> Map<Integer,T> getBeanMap(Class<T> clazz) {
        Map<Integer,T> map = new HashMap<>();
        String name = clazz.getSimpleName().replaceAll("Data","");
        if(context.containsKey(name)) {
            Map<Integer, Map<String, Object>> beanMap = context.get(name);
            beanMap.forEach((k, v) -> map.putIfAbsent(k, BeanUtil.toBean(v, clazz)));
        }
        return map;
    }
}
